home *** CD-ROM | disk | FTP | other *** search
- PROGRAM dotcube2;
- {
- Dotcube2
- - by Bjarke Viksφe
- aug 1994
-
- Screen mode is 320x200x16.
- Buffer in made 256 bytes wide, so we can address (x,y) fast.
- When box is drawn, buffer is copied to display screen.
- Plots 3072 dots, when it's doing 3 faces!
- Notice that only 8 coords are actually rotated. The rest are based
- on those 8 plots.
- I take 2 opposite lines in each face and split them into
- 16 parts. And dotted lines (16 dots pr. line) are then drawn between
- each new line that comes out of the split.
- Try to fiddle with the "NUMBER_SPLITS" value to see how many you can
- get. On my 40Mhz '486 I can get around 17000 dots at 70 fps.
- And it can still be optimized. Unroll a few loops and you'll see...
- }
-
- {$A+,B-,G+,E+,I+,N-,X+}
- {$C FIXED PRELOAD PERMANENT}
-
-
- USES
- DEMOINIT;
-
- {$DEFINE DEBUG}
-
- CONST
- NUMBER_FACES = 6;
- NUMBER_COORDS = 8;
- BOX = 110; {size of box}
- NUMBER_SPLITS = 32; {number of pieces each line is broken into}
-
- TYPE
- facetype = RECORD
- l1,l2,l3,l4 : byte;
- end;
- slopearray = array[0..NUMBER_SPLITS] of integer;
-
- VAR
- SlopeX1 : slopearray;
- SlopeY1 : slopearray;
- SlopeX2 : slopearray;
- SlopeY2 : slopearray;
- face : array[1..NUMBER_FACES] of facetype;
- cbuffer : array[0..NUMBER_COORDS*2-1] of integer;
-
- sinustabel : array[0..639] of integer;
- v1,v2,v3 : word; {angle of x,y,z axis}
- cos1,sin1,cos2,sin2,cos3,sin3 : integer;
-
- xkoord,ykoord,zkoord,
- n : integer;
-
- buffer : pScreen;
-
-
- CONST
- display1 : word = $0000;
- display2 : word = $4000;
- display3 : word = $8000;
- {coordinates for box}
- coords : array[0..NUMBER_COORDS*3-1] of integer =
- (box,box,-box, -box,box,-box, -box,-box,-box, box,-box,-box,
- box,box,box, -box,box,box, -box,-box,box, box,-box,box);
-
-
-
- (*------------------------------------------------*)
-
- procedure SetupSinus;
- var
- i : integer;
- v, vadd : real;
- begin
- v:=0.0;
- vadd:=(2.0*pi/512.0);
- for i:=0 to 639 do begin
- sinustabel[i]:=round(sin(v)*32767);
- v:=v+vadd;
- end;
- end;
-
- procedure SetupFaces;
- begin
- with face[1] do begin l1:=3; l2:=2; l3:=0; l4:=1; end;
- with face[2] do begin l1:=4; l2:=5; l3:=7; l4:=6; end;
- with face[3] do begin l1:=0; l2:=1; l3:=4; l4:=5; end;
- with face[4] do begin l1:=1; l2:=2; l3:=5; l4:=6; end;
- with face[5] do begin l1:=2; l2:=3; l3:=6; l4:=7; end;
- with face[6] do begin l1:=3; l2:=0; l3:=7; l4:=4; end;
- end;
-
-
- (*------------------------------------------------*)
-
- procedure InitDemo;
- var
- p : pointer;
- i : integer;
- begin
- ClearWholeScreen;
- SetupSinus;
- SetupFaces;
-
- {allocate memory for buffer. Offset MUST be $0000 though!!!}
- New(buffer);
- while Ofs(buffer^)<>0 do begin
- Dispose(buffer);
- GetMem(p,1); {does this really work? Think not!}
- New(buffer);
- end;
- FillChar(buffer^,SizeOf(ScreenType),#0);
- end;
-
- procedure UninitDemo;
- var
- i : integer;
- begin
- Dispose(buffer);
- end;
-
-
- (*------------------------------------------------*)
-
- procedure SwapDisplay;
- var
- temp : word;
- begin
- temp:=display3;
- display3:=display2;
- display2:=display1;
- display1:=temp;
- SetAddress(Ptr(SEGA000,display2));
- end;
-
- procedure MoveBuffer; assembler;
- {Move buffer to display memory}
- asm
- push ds
-
- mov es,SEGA000
- mov di,display1
- add di,(36*40)+12 {center on display screen}
- lds si,buffer
- xor ax,ax
- mov bx,-2
- mov dx,128 {ysize}
- cld
- @yloop:
- mov cl,8
- @xloop:
- movsw {move buffer word to video memory}
- mov [si+bx],ax {clear the buffer again}
- dec cl
- jnz @xloop
-
- add si,256-16
- add di,40-16
- dec dx
- jnz @yloop
-
- pop ds
- end;
-
- (*------------------------------------------------*)
-
- procedure CalcAngle;
- {Change rotation angle}
- begin
- sin1:=sinustabel[v1]; cos1:=sinustabel[v1+128];
- sin2:=sinustabel[v2]; cos2:=sinustabel[v2+128];
- sin3:=sinustabel[v3]; cos3:=sinustabel[v3+128];
- v1:=(v1-1) AND 511;
- v2:=(v2-2) AND 511;
- v3:=(v3+1) AND 511;
- end;
-
- procedure RotateAllCoords;
- var
- i, a,b : integer;
- x,y,z : longint;
- temp : integer;
- begin
- a:=0; b:=0;
- for i:=1 to NUMBER_COORDS do begin
- x:=coords[a]; y:=coords[a+1]; z:=coords[a+2];
- inc(a,3);
-
- temp:=y;
- y:=(LongMul(y,cos1) - LongMul(z,sin1)) DIV 32768;
- z:=(LongMul(temp,sin1) + LongMul(z,cos1)) DIV 32768;
- temp:=x;
- x:=(LongMul(x,cos2) + LongMul(z,sin2)) DIV 32768;
- z:=(LongMul(z,cos2) - LongMul(temp,sin2)) DIV 32768;
- temp:=x;
- x:=(LongMul(x,cos3) - LongMul(y,sin3)) DIV 32768;
- y:=(LongMul(temp,sin3) + LongMul(y,cos3)) DIV 32768;
-
- cbuffer[b]:=((x SHL 8) DIV (z+800))+64;
- cbuffer[b+1]:=((y SHL 8) DIV (z+800))+64;
- inc(b,2);
- end;
- end;
-
-
- function FaceShown(i : integer; l1,l2,l3 : byte) : boolean;
- {Is the face turning the back on us?}
- var
- a,b : longint;
- begin
- a := longmul(cbuffer[l1]-cbuffer[l2],cbuffer[l3+1]-cbuffer[l2+1]);
- b := longmul(cbuffer[l1+1]-cbuffer[l2+1],cbuffer[l3]-cbuffer[l2]);
- FaceShown := (a-b) > 0;
- end;
-
-
- (*------------------------------------------------*)
-
- procedure CalcSlope(x1,y1,x2,y2 : integer; table1,table2 : pointer); assembler;
- {Calc points between 2 set of coords}
- asm
- DB LONG; xor cx,cx
-
- mov cx,NUMBER_SPLITS+1 {Split x-line into parts}
- mov ax,x2
- sub ax,x1
- DB LONG; shl ax,16
- {cdq} DB $66,$99
- DB LONG; idiv cx
- DB LONG; mov si,ax
- DB LONG; mov dx,ax
- DB LONG; shr dx,16
-
- les di,table1
- mov ax,x1
- xor bx,bx
- mov cx,NUMBER_SPLITS
- @xloop:
- add bx,si
- adc ax,dx
- stosw
- dec cx
- jnz @xloop
-
- mov cx,NUMBER_SPLITS+1 {Split y-line into parts}
- mov ax,y2
- sub ax,y1
- DB LONG; shl ax,16
- {cdq} DB $66,$99
- DB LONG; idiv cx
- DB LONG; mov si,ax
- DB LONG; mov dx,ax
- DB LONG; shr dx,16
-
- les di,table2
- mov ax,y1
- xor bx,bx
- mov cx,NUMBER_SPLITS
- @yloop:
- add bx,si
- adc ax,dx
- stosw
- dec cx
- jnz @yloop
- end;
-
-
- procedure DrawDottedLine(x1,y1,x2,y2 : integer); assembler;
- {Draws a line, but splits it up into NUMBER_SPLITS parts and makes
- dots instead}
- asm
- mov cx,NUMBER_SPLITS+1 {break line into n pieces}
-
- mov ah,BYTE PTR x2
- sub ah,BYTE PTR x1
- xor al,al
- cwd
- idiv cx
- mov di,ax
-
- mov ah,BYTE PTR y2
- sub ah,BYTE PTR y1
- xor al,al
- cwd
- idiv cx
- {we need to set AX to BP later, so does mess up AX...}
-
- mov bh,BYTE PTR x1
- xor bl,bl
- mov dh,BYTE PTR y1
- xor dl,dl
-
- mov ch,NUMBER_SPLITS
- push bp
- mov bp,ax
-
- mov es,WORD PTR buffer+2
-
- @loop:
- add bx,di {add to x}
- add dx,bp {add to y}
- mov al,bh
- mov cl,al {make a copy of x}
- shr al,3 {calc x address-offset}
- mov ah,dh {get y pos. Since width is 256 bytes, this is easy}
- mov si,ax
- mov al,$80 {calc bit pos}
- ror al,cl
- or [es:si],al
- dec ch {loop. ("dec cx, jnz.." is faster than "LOOP @loop")}
- jnz @loop
-
- pop bp
- end;
-
-
- (*------------------------------------------------*)
-
- procedure RunOnce;
- var
- i,j : integer;
- begin
- SwapDisplay;
- {$IFNDEF DEBUG}
- while retraces=0 do ;
- retraces:=0;
- {$ELSE}
- VBLANK;
- SetRGB(0,20,0,0);
- {$ENDIF}
-
- CalcAngle;
- RotateAllCoords;
-
- for i:=1 to NUMBER_FACES do begin
- with face[i] do if FaceShown(i, l1 shl 1,l2 shl 1,l3 shl 1) then begin
- CalcSlope(cbuffer[(l1 SHL 1)],cbuffer[(l1 SHL 1)+1], cbuffer[(l2 SHL 1)],cbuffer[(l2 SHL 1)+1], @SlopeX1,@SlopeY1);
- CalcSlope(cbuffer[(l3 SHL 1)],cbuffer[(l3 SHL 1)+1], cbuffer[(l4 SHL 1)],cbuffer[(l4 SHL 1)+1], @SlopeX2,@SlopeY2);
- for j:=0 to NUMBER_SPLITS-1 do
- DrawDottedLine(SlopeX1[j],SlopeY1[j],SlopeX2[j],SlopeY2[j]);
- end;
- end;
-
- MoveBuffer;
-
- {$IFDEF DEBUG}
- SetRGB(0,0,0,0);
- while KeyHit[26] do ; {Hit 'P' to pause in debug mode}
- {$ENDIF}
- end;
-
-
- begin
- SetScreenMode($D);
- Screen_Off;
- InitDemo;
- Screen_On;
- SetAllInterrupts;
- repeat RunOnce until Key='e'; {press ESCape key to exit}
- RestoreAllInterrupts;
- UninitDemo;
- SetScreenMode(TEXTMODE);
- end.
-